package com.dss.auto_deploy.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dss.auto_deploy.config.DssProperties;
import com.dss.auto_deploy.config.WebsocketEndPoint;
import com.dss.auto_deploy.constants.AutoConstants;
import com.dss.auto_deploy.domain.*;
import com.dss.auto_deploy.dto.*;
import com.dss.auto_deploy.enums.DockerDeployStatusEnum;
import com.dss.auto_deploy.event.DockerPullAndStartEvent;
import com.dss.auto_deploy.mapper.*;
import com.dss.auto_deploy.service.*;
import com.dss.auto_deploy.util.*;
import com.dss.auto_deploy.util.mail.MailUtil;
import com.dss.auto_deploy.util.mail.MyEmail;
import com.dss.auto_deploy.vo.AdmDockerDeployVo;
import com.dss.auto_deploy.vo.AdmDockerVo;
import com.dss.auto_deploy.vo.AllDockerInfoVo;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.async.ResultCallback;
import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.model.*;
import com.jcraft.jsch.Session;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author dongshoushan
 * @Description:docker部署项目模块配置Service实现类
 * @date 2022-09-22 14:38:57
 */
@Service
@Slf4j
@RequiredArgsConstructor(onConstructor = @_(@Autowired))
public class AdmDockerDeployServiceImpl extends ServiceImpl<AdmDockerDeployMapper, AdmDockerDeploy> implements IAdmDockerDeployService {

    /**
     * docker部署项目模块配置Mapper
     */
    private final AdmDockerDeployMapper admDockerDeployMapper;
    private final RemoteSshUtil remoteSshUtil;
    private final ThreadPoolTaskExecutor threadPoolTaskExecutor;
    private final ApplicationEventPublisher publisher;
    private final WebsocketEndPoint websocketEndPoint;
    private final DssProperties dssProperties;
    private final AdmDockerMapper admDockerMapper;
    private final IServerService serverService;
    private final AdmDockerRegistryMapper admDockerRegistryMapper;
    private final DockerUtil dockerUtil;
    private final MailUtil mailUtil;
    private final IAdmRegistryTagHstService admRegistryTagHstService;
    private final IAdmDockerService admDockerService;
    private final AdmRegistryTagHstMapper admRegistryTagHstMapper;
    private final AdmNamespaceMapper admNamespaceMapper;
    private final IAdmNamespaceService admNamespaceService;
    private final AdmHostsMapper admHostsMapper;
    private final AdmNacosMapper admNacosMapper;
    private final AdmProjectAutoConfigMapper admProjectAutoConfigMapper;
    private final AdmProjectMapper admProjectMapper;
    private final IAdmDockerRegistryService admDockerRegistryService;
    private final CacheUtils cacheUtils;

    public static HashMap<Integer, Integer> getMap() {
        map.put(0, 0);
        map.put(1, 20);
        map.put(2, 30);
        map.put(3, 40);
        map.put(4, 50);
        map.put(5, 60);
        map.put(6, 70);
        map.put(7, 80);
        map.put(8, 90);
        map.put(9, 100);
        map.put(10, 30);
        map.put(11, 90);
        return map;
    }

    public static HashMap<Integer, Integer> map = new HashMap<>(16);

    /**
     * 新增docker部署项目模块配置
     *
     * @param admDockerDeployAddDto
     * @return Long
     */
    @Override
    public Long insert(AdmDockerDeployAddDto admDockerDeployAddDto) {
        AdmDockerDeploy admDockerDeploy = BeanUtils.copy(admDockerDeployAddDto, AdmDockerDeploy.class);
        admDockerDeploy.setDeployStatus(DockerDeployStatusEnum.INIT.getCode());
        check(admDockerDeploy);
        int insert = admDockerDeployMapper.insert(admDockerDeploy);
        if (insert == 1) {
            log.info("新增成功{}", JacksonUtils.toString(admDockerDeploy));
        }
        return admDockerDeploy.getId();
    }

    private void check(AdmDockerDeploy deploy) {
        Long namespaceId = deploy.getNamespaceId();
        AdmNamespace admNamespace = admNamespaceMapper.selectById(namespaceId);
        if (admNamespace.getRegistryId() == null) {
            throw new ServiceException("此命名空间未设置docker仓库");
        }
        List<AdmDockerDeploy> list = admDockerDeployMapper.selectList(Wrappers.lambdaQuery(AdmDockerDeploy.class)
                .eq(AdmDockerDeploy::getDockerId, deploy.getDockerId())
                .eq(AdmDockerDeploy::getModuleName, deploy.getModuleName())
                .ne(deploy.getId() != null, AdmDockerDeploy::getId, deploy.getId())
        );
        if (CollectionUtil.isNotEmpty(list)) {
            throw new ServiceException("此节点容器节点名称已存在,请重新设置");
        }
    }


    /**
     * 修改docker部署项目模块配置
     *
     * @param admDockerDeployUpdateDto
     * @return Long
     */
    @Override
    public int update(AdmDockerDeployUpdateDto admDockerDeployUpdateDto) {
        AdmDockerDeploy admDockerDeploy = BeanUtils.copy(admDockerDeployUpdateDto, AdmDockerDeploy.class);
        check(admDockerDeploy);
        int number = admDockerDeployMapper.updateById(admDockerDeploy);
        if (number == 1) {
            log.info("修改成功{}", JacksonUtils.toString(admDockerDeploy));
        }
        return number;
    }


    /**
     * 批量删除docker部署项目模块配置
     *
     * @param ids
     * @return Long
     */
    @Override
    public void deleteBatch(Long[] ids) {
        List<AdmDockerDeploy> deployList = admDockerDeployMapper.selectBatchIds(Arrays.asList(ids));
        deployList.forEach(deploy -> {
            threadPoolTaskExecutor.execute(() -> {
                try {
                    AdmDocker admDocker = admDockerMapper.selectById(deploy.getDockerId());
                    DockerClient dockerClient = dockerUtil.getDockerClientByDocker(SpringUtils.getBean(AdmDockerServiceImpl.class).convertToVo(admDocker));
                    Container container = dockerClient.listContainersCmd().withShowAll(true).exec().stream().filter(d -> deploy.getContainerId().equals(d.getId())).findFirst().orElse(null);
                    if (container != null) {
                        dockerClient.removeContainerCmd(deploy.getContainerId()).withForce(true).withRemoveVolumes(true).exec();
                        log.info("移除容器:{}", JacksonUtils.toString(deploy));
                    }
                    dockerUtil.close(dockerClient);
                } catch (Exception e) {
                    log.error(e.getMessage());
                }
            });
        });
        this.removeByIds(Arrays.asList(ids));
    }

    /**
     * docker部署项目模块配置分页查询
     *
     * @param pageDto
     * @return List<AdmDockerDeploy>
     */
    @Override
    public Page<AdmDockerDeployVo> list(AdmDockerDeployPageDto pageDto) throws InterruptedException {
        Page<AdmDockerDeploy> tablesPage = new Page<>(pageDto.getPage(), pageDto.getLimit());
        LambdaQueryWrapper<AdmDockerDeploy> queryWrapper = Wrappers.lambdaQuery(AdmDockerDeploy.class)
                .like(StringUtils.isNotEmpty(pageDto.getContent()), AdmDockerDeploy::getModuleName, pageDto.getContent())
                .eq(StringUtils.isNotEmpty(pageDto.getModuleName()), AdmDockerDeploy::getModuleName, pageDto.getModuleName())
                .eq(pageDto.getDockerId() != null, AdmDockerDeploy::getDockerId, pageDto.getDockerId())
                .eq(pageDto.getNamespaceId() != null, AdmDockerDeploy::getNamespaceId, pageDto.getNamespaceId())
                .eq(pageDto.getProjectId() != null, AdmDockerDeploy::getProjectId, pageDto.getProjectId())
                .orderByDesc(AdmDockerDeploy::getLastDeployDate);
        Page<AdmDockerDeploy> pageSelectResult = admDockerDeployMapper.selectPage(tablesPage, queryWrapper);
        List<AdmDockerDeploy> records = pageSelectResult.getRecords();
        List<AdmDockerDeployVo> voList = convertToVo(records);
        Page<AdmDockerDeployVo> page = new Page<>();
        page.setRecords(voList);
        page.setTotal(pageSelectResult.getTotal());
        page.setSize(pageSelectResult.getSize());
        return page;
    }

    private List<AdmDockerDeployVo> convertToVo(List<AdmDockerDeploy> records) throws InterruptedException {
        if (records == null || records.isEmpty()) {
            return new ArrayList<>();
        }
        List<AdmDockerDeployVo> deployVoList = BeanUtils.copyList(records, AdmDockerDeployVo.class);
        List<AdmProject> admProjects = SpringUtils.getBean(AdmProjectServiceImpl.class).getAll();
        List<Long> dockerIds = deployVoList.stream().map(AdmDockerDeployVo::getDockerId).collect(Collectors.toList());
        List<AdmDocker> dockers = admDockerService.getAll().stream().filter(s->dockerIds.contains(s.getId())).collect(Collectors.toList());
        List<AdmDockerVo> admDockers = admDockerService.convertToVo(dockers);
        List<AdmNamespace> admNamespaces = SpringUtils.getBean(AdmNamespaceServiceImpl.class).getAll();
        List<AdmNacos> admNacosList = SpringUtils.getBean(AdmNacosServiceImpl.class).getAll();
        List<Server> serverList = serverService.getAll();
        List<AdmDockerRegistry> admDockerRegistries = SpringUtils.getBean(AdmDockerRegistryServiceImpl.class).getAll();
        Map<String, List<Container>> containerMap = admDockerService.getContainerMapByVo(admDockers);
        deployVoList.forEach(vo -> {
            vo.setProjectName(admProjects.stream().filter(s -> s.getId().equals(vo.getProjectId())).findFirst().orElse(null).getProjectName());
            AdmDockerVo admDockerVo = admDockers.stream().filter(s -> s.getId().equals(vo.getDockerId())).findFirst().orElse(null);
            AdmNamespace admNamespace = admNamespaces.stream().filter(s -> s.getId().equals(vo.getNamespaceId())).findFirst().orElse(null);
            AdmNacos admNacos = admNacosList.stream().filter(s -> s.getId().equals(vo.getNacosId())).findFirst().orElse(null);
            Long serverId = admDockerVo.getServerId();
            Server server = serverList.stream().filter(s -> s.getId().equals(serverId)).findFirst().orElse(null);
            AdmDockerRegistry admDockerRegistry = admDockerRegistries.stream().filter(s -> s.getId().equals(admNamespace.getRegistryId())).findFirst().orElse(null);
            vo.setIp(server.getIp());
            vo.setRegistryName(admDockerRegistry.getRegistryName());
            vo.setDockerName(admDockerVo.getDockerName());
            vo.setDeployStatusName(EnumUtils.getDescByCode(DockerDeployStatusEnum.class, vo.getDeployStatus()));
            vo.setNamespaceName(admNamespace.getName());
            vo.setNacosName(admNacos != null ? admNacos.getNacosName() : null);
            HashMap<Integer, Integer> map = getMap();
            for (Integer integer : map.keySet()) {
                if (vo.getDeployStatus().equals(integer)) {
                    vo.setProgressBar(map.get(integer));
                    break;
                }
            }
            List<Container> containers = containerMap.get("AdmDockerVo" + admDockerVo.getId());
            Container container = containers.stream().filter(s -> s.getId().equals(vo.getContainerId())).findFirst().orElse(null);
            if (container == null) {
                vo.setContainerStatusName("未创建或超时");
            } else {
                vo.setContainerStatusName(container.getState());
            }
        });
        return deployVoList;
    }



    private void dockerDeployHst(AdmDockerDeploy admDockerDeploy, Long registryId, Long namespaceId) {
        //仓库历史记录
        List<AdmRegistryTagHst> registryTagHstList = admRegistryTagHstMapper.selectList(Wrappers.lambdaQuery(AdmRegistryTagHst.class)
                .eq(AdmRegistryTagHst::getRegistryId, registryId)
                .eq(AdmRegistryTagHst::getNamespaceId, namespaceId)
                .eq(AdmRegistryTagHst::getImageName, admDockerDeploy.getModuleName())
        );
        List<AdmRegistryTagHst> collect2 = registryTagHstList.stream().filter(admRegistryTagHst -> admDockerDeploy.getTag().equals(admRegistryTagHst.getTag())).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(collect2)) {
            AdmRegistryTagHst registryTagHst = AdmRegistryTagHst.builder().projectId(admDockerDeploy.getProjectId()).registryId(registryId).updateTime(new Date())
                    .namespaceId(namespaceId).imageName(admDockerDeploy.getModuleName()).tag(admDockerDeploy.getTag()).createTime(new Date()).build();
            admRegistryTagHstMapper.insert(registryTagHst);
        } else {
            for (AdmRegistryTagHst admRegistryTagHst : collect2) {
                admRegistryTagHst.setUpdateTime(new Date());
                admRegistryTagHstMapper.updateById(admRegistryTagHst);
            }
        }
    }

    /**
     * 弹窗提示
     *
     * @param data
     */
    @Override
    public void alertSuccessMsg(String data) {
        websocketEndPoint.send(WsSendDto.builder().type(2).table("deployDocker").data(data).build());
    }

    /**
     * 弹窗提示
     *
     * @param data
     */
    @Override
    public void alertFailMsg(String data) {
        websocketEndPoint.send(WsSendDto.builder().type(3).table("deployDocker").data(data).build());
    }

    /**
     * 仅刷新表格
     */
    @Override
    public void reloadHtml() {
        websocketEndPoint.send(WsSendDto.builder().type(1).table("deployDocker").build());
    }


    /**
     * docker部署上传仓库服务器
     *
     * @param dockerDeploy
     */
    @Override
    public void uploadService(AdmDockerDeploy dockerDeploy) throws IOException {
        long start = System.currentTimeMillis();
        Long namespaceId = dockerDeploy.getNamespaceId();
        AdmNamespace admNamespace = admNamespaceMapper.selectById(namespaceId);
        AdmDockerRegistry admDockerRegistry = admDockerRegistryMapper.selectById(admNamespace.getRegistryId());
        //部署宿主机docker
        AdmDocker admDocker = admDockerMapper.selectById(dockerDeploy.getDockerId());
        //仓库虚拟机
        Server registryServer = serverService.getServerById(admDockerRegistry.getServerId());
        //仓库所在docker
        AdmDocker registryDocker = admDockerService.getByIp(registryServer.getIp());
        //部署宿主机
        Server dockerServer = serverService.getServerById(admDocker.getServerId());
        Session session = null;
        try {
            List<AdmDockerDeploy> list = this.list(Wrappers.lambdaQuery(AdmDockerDeploy.class).eq(AdmDockerDeploy::getProjectId, dockerDeploy.getProjectId())
                    .eq(AdmDockerDeploy::getNamespaceId, dockerDeploy.getNamespaceId())
                    .eq(AdmDockerDeploy::getEnable, 0)
                    .eq(AdmDockerDeploy::getModuleName, dockerDeploy.getModuleName()));
            //上传到仓库
            session = remoteSshUtil.connect(registryServer);
            String startUploadInfo = StringUtils.format("{} 开始上传项目模块：{}到docker仓库ip：{}", DateUtil.now(), dockerDeploy.getModuleName(), registryServer.getIp());
            FileUtils.writeDockerFileInRealTime(startUploadInfo);
            for (AdmDockerDeploy admDockerDeploy : list) {
                FileUtils.writeDockerFileByPath(admDockerDeploy, startUploadInfo);
                admDockerDeploy.setDeployStatus(DockerDeployStatusEnum.UPLOAD.getCode());
                admDockerDeployMapper.updateById(admDockerDeploy);
            }
            reloadHtml();
            //sftp上传文件
            remoteSshUtil.putJarDockerFile(session, dockerDeploy, registryServer);
            //Dockerfile生成以及上传
            Map map = new HashMap<String, Object>(2);
            String localFile = dockerDeploy.getLocalFile();
            String temp;
            if (localFile.contains("\\")) {
                temp = "\\\\";
            } else {
                temp = "/";
            }
            String[] split = localFile.split(temp);
            String jarName = split[split.length - 1];
            map.put("jarName", jarName);
            List<JdkVersionDto> jdkVersionList = AutoConstants.JDK_VERSION_LIST;
            String jdkVersion = dockerDeploy.getJdkVersion();
            JdkVersionDto jdkVersionDto = jdkVersionList.stream().filter(s -> s.getKey().equals(jdkVersion)).findFirst().get();
            map.put("jdkVersion", jdkVersionDto.getValue());
            if (jdkVersionDto.getVersion() >= 17) {
                map.put("enablePreview", "--enable-preview");
            } else {
                map.put("enablePreview", "");
            }
            map.put("env", "");
            if (StringUtils.isNotEmpty(dockerDeploy.getEnvs())) {
                List<EnvDto> envDtoList = JacksonUtils.toList(dockerDeploy.getEnvs(), EnvDto.class);
                if (StringUtils.isNotEmpty(envDtoList)) {
                    // 拼接环境变量
                    String envString = envDtoList.stream()
                            .map(env -> {
                                if (StringUtils.isNotEmpty(env.getValue())) {
                                    return StringUtils.format("\"{}={}\"", env.getKey(), env.getValue());
                                } else {
                                    return StringUtils.format("\"{}\"", env.getKey());
                                }
                            })
                            .collect(Collectors.joining(", "));
                    map.put("env", envString + ",");
                }
            }
            String fileLocalPath = AutoConstants.baseLocalPath + dockerDeploy.getId() + "/Dockerfile";
            FileUtils.generateFileByTemplate("Dockerfile.ftl", fileLocalPath, AutoConstants.baseLocalPath + dockerDeploy.getId(), map);
            remoteSshUtil.putFile(session, fileLocalPath, dockerDeploy.getRemoteTargetDirectory());
            //防止因为异步操作进度未来得及更新获取的不是最新的，等3秒重新查询结果
            Thread.sleep(3000);
            dockerDeploy = getById(dockerDeploy.getId());
            String uploadSuccessInfo = StringUtils.format("{} 上传项目模块：{}到docker仓库ip：{}成功,上传耗时：{}秒", DateUtil.now(), dockerDeploy.getModuleName(), registryServer.getIp(), (System.currentTimeMillis() - start) / 1000);
            FileUtils.writeDockerFileInRealTime(uploadSuccessInfo);
            for (AdmDockerDeploy admDockerDeploy : list) {
                FileUtils.writeDockerFileByPath(admDockerDeploy, uploadSuccessInfo);
            }
            reloadHtml();
            DockerClient registryDockerClient = dockerUtil.getDockerClientByDocker(SpringUtils.getBean(AdmDockerServiceImpl.class).convertToVo(registryDocker));
            dockerUtil.delImageByName(registryDockerClient, dockerDeploy.getModuleName());
            bulidImage(dockerDeploy);
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage());
            deployError(dockerDeploy, e.getMessage(), dockerServer);
        } finally {
            remoteSshUtil.close(session);
        }
    }

    @Override
    public void bulidImage(AdmDockerDeploy dockerDeploy) throws Exception {
        Long namespaceId = dockerDeploy.getNamespaceId();
        AdmNamespace admNamespace = admNamespaceMapper.selectById(namespaceId);
        AdmDockerRegistry admDockerRegistry = admDockerRegistryMapper.selectById(admNamespace.getRegistryId());
        //仓库虚拟机
        Server registryServer = serverService.getServerById(admDockerRegistry.getServerId());
        //仓库所在docker
        AdmDocker registryDocker = admDockerService.getByIp(registryServer.getIp());
        DockerClient registryDockerClient = dockerUtil.getDockerClientByDocker(SpringUtils.getBean(AdmDockerServiceImpl.class).convertToVo(registryDocker));
        //先删除镜像再构建，防止堆积
        delRegistry(registryServer, admDockerRegistry, dockerDeploy.getModuleName(), dockerDeploy.getTag());
        bulidImage(registryDockerClient, registryServer, dockerDeploy, admDockerRegistry);
        dockerDeployHst(dockerDeploy, admNamespace.getRegistryId(), namespaceId);
        //删除多余历史版本，只保留最近的几个版本
        delHstTag(dockerDeploy.getModuleName(), admNamespace.getRegistryId());
        //pushImageCmd(registryDockerClient, imageName, dockerDeploy);

    }


    /**
     * docker镜像构建
     *
     * @throws Exception
     */
    public synchronized void bulidImage(DockerClient dockerClient, Server registryServer, AdmDockerDeploy admDockerDeploy, AdmDockerRegistry admDockerRegistry) throws Exception {
        List<AdmDockerDeploy> list = this.list(Wrappers.lambdaQuery(AdmDockerDeploy.class).eq(AdmDockerDeploy::getProjectId, admDockerDeploy.getProjectId())
                .eq(AdmDockerDeploy::getNamespaceId, admDockerDeploy.getNamespaceId())
                .eq(AdmDockerDeploy::getEnable, 0)
                .eq(AdmDockerDeploy::getModuleName, admDockerDeploy.getModuleName()));
        String command = StringUtils.format("cd {} && docker build -t {}:{}/{}:{} .", admDockerDeploy.getRemoteTargetDirectory(), registryServer.getIp(), admDockerRegistry.getPort(),
                admDockerDeploy.getModuleName(), admDockerDeploy.getTag());
        admDockerDeploy.setDeployStatus(DockerDeployStatusEnum.BUILD_IMAGE.getCode());
        System.out.println(command);
        String info = StringUtils.format("{} docker镜像{}开始构建", DateUtil.now(), admDockerDeploy.getModuleName());
        FileUtils.writeDockerFileInRealTime(info);
        for (AdmDockerDeploy dockerDeploy : list) {
            FileUtils.writeDockerFileByPath(dockerDeploy, info);
            FileUtils.writeDockerFileByPath(dockerDeploy, command);
            admDockerDeployMapper.updateById(dockerDeploy);
        }
        reloadHtml();
        Session session = null;
        try {
            session = remoteSshUtil.connect(registryServer);
            String exec = remoteSshUtil.exec(command, session);
            //System.out.println(exec);
            FileUtils.writeDockerFileByPath(admDockerDeploy, exec);
            String imageName = StringUtils.format("{}:{}/{}:{}", registryServer.getIp(), admDockerRegistry.getPort(), admDockerDeploy.getModuleName(), admDockerDeploy.getTag());
            long start = System.currentTimeMillis();
            while (true) {
                List<Image> imageList = dockerClient.listImagesCmd().exec().stream().filter(image -> image.getRepoTags() != null
                        && image.getRepoTags()[0].contains(imageName)).collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(imageList)) {
                    reloadHtml();
                    String uploadSuccessInfo = StringUtils.format("{} 镜像：{}构建成功", DateUtil.now(), admDockerDeploy.getModuleName());
                    FileUtils.writeDockerFileInRealTime(uploadSuccessInfo);
                    for (AdmDockerDeploy dockerDeploy : list) {
                        dockerDeploy.setDeployStatus(DockerDeployStatusEnum.BUILD_IMAGE_SUCCESS.getCode());
                        admDockerDeployMapper.updateById(dockerDeploy);
                        FileUtils.writeDockerFileByPath(dockerDeploy, uploadSuccessInfo);
                    }
                    break;
                }
                if (System.currentTimeMillis() - start > 30 * 1000) {
                    System.out.println("===============当前构建docker镜像已超过30秒，进行重试============");
                    String exec2 = remoteSshUtil.exec(command, session);
                    System.out.println(exec2);
                    FileUtils.writeDockerFileByPath(admDockerDeploy, exec2);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            remoteSshUtil.close(session);
        }

    }

    /**
     * 推送
     *
     * @param dockerClient
     * @param imageName
     * @param admDockerDeploy
     */
    @Override
    public void pushImageCmd(DockerClient dockerClient, String imageName, AdmDockerDeploy admDockerDeploy) {
        List<AdmDockerDeploy> list = this.list(Wrappers.lambdaQuery(AdmDockerDeploy.class).eq(AdmDockerDeploy::getProjectId, admDockerDeploy.getProjectId())
                .eq(AdmDockerDeploy::getNamespaceId, admDockerDeploy.getNamespaceId())
                .eq(AdmDockerDeploy::getEnable, 0)
                .eq(AdmDockerDeploy::getModuleName, admDockerDeploy.getModuleName()));
        dockerClient.pushImageCmd(imageName).exec(new ResultCallback<PushResponseItem>() {
            @Override
            public void onStart(Closeable closeable) {
                String info = StringUtils.format("{} 推送镜像：{}到仓库ing", DateUtil.now(), imageName);
                try {
                    FileUtils.writeDockerFileInRealTime(info);
                    for (AdmDockerDeploy dockerDeploy : list) {
                        FileUtils.writeDockerFileByPath(dockerDeploy, info);
                    }
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }

            @Override
            public void onNext(PushResponseItem pushResponseItem) {
                //if (StringUtils.isNotEmpty(pushResponseItem.getProgress())) {
                //    String info = pushResponseItem.getStatus() + "" + pushResponseItem.getProgress();
                //    try {
                //        for (AdmDockerDeploy dockerDeploy : list) {
                //            FileUtils.writeDockerFileByPath(dockerDeploy, info);
                //        }
                //    } catch (IOException e) {
                //        throw new RuntimeException(e);
                //    }
                //    System.out.println(pushResponseItem.getStatus() + "" + pushResponseItem.getProgress());
                //}
            }

            @Override
            public void onError(Throwable throwable) {
                throwable.printStackTrace();
            }

            @Override
            public void onComplete() {
                String info = StringUtils.format("{} 推送仓库成功等待拉取镜像：{}", DateUtil.now(), imageName);
                try {
                    FileUtils.writeDockerFileInRealTime(info);
                    for (AdmDockerDeploy dockerDeploy : list) {
                        dockerDeploy.setDeployStatus(DockerDeployStatusEnum.PUSH.getCode());
                        admDockerDeployMapper.updateById(dockerDeploy);
                        FileUtils.writeDockerFileByPath(dockerDeploy, info);
                    }
                    publisher.publishEvent(new DockerPullAndStartEvent(admDockerDeploy, imageName));
                    //DockerDeployMqDto mqDto = DockerDeployMqDto.builder().admDockerDeploy(admDockerDeploy).imageName(imageName).build();
                    //rabbitSender.sendRabbitMQ(MqMsgVo.builder().exchangeName(DEPLOY_EXCHANGE).data(mqDto).build());
                    reloadHtml();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }

            @Override
            public void close() {
                System.out.println("关闭");
            }
        });
    }

    /**
     * 删除多余历史版本，只保留最近的几个版本
     *
     * @param imageName
     */
    public void delHstTag(String imageName, Long registryId) {
        List<AdmRegistryTagHst> registryTagHstList = admRegistryTagHstMapper.selectList(Wrappers.lambdaQuery(AdmRegistryTagHst.class)
                .eq(AdmRegistryTagHst::getRegistryId, registryId).eq(AdmRegistryTagHst::getImageName, imageName).orderByDesc(AdmRegistryTagHst::getCreateTime));
        Integer integer = registryTagHstList.size() - dssProperties.getTagNumber();
        Server server = serverService.getServerByRegistryId(registryId);
        AdmDockerRegistry admDockerRegistry = admDockerRegistryMapper.selectById(registryId);
        if (integer > 0) {
            //要删除的版本
            for (int i = 0; i < integer; i++) {
                AdmRegistryTagHst admRegistryTagHst = registryTagHstList.get(i);
                System.out.println("删除多余版本" + JacksonUtils.toString(admRegistryTagHst));
                admRegistryTagHstMapper.deleteById(admRegistryTagHst.getId());
                try {
                    //删除仓库
                    delRegistry(server, admDockerRegistry, imageName, admRegistryTagHst.getTag());
                } catch (Exception e) {
                    throw new ServiceException("连接失败");
                }
            }
        }
    }

    /**
     * 清除仓库
     *
     * @param server
     * @param admDockerRegistry
     * @param imageName
     * @param tag
     */
    @Override
    public void delRegistry(Server server, AdmDockerRegistry admDockerRegistry, String imageName, String tag) {
        //System.out.println("=============开始清理仓库之前的旧镜像===========");
        Session session = null;
        try {
            session = remoteSshUtil.connect(server);
            String getSh256 = StringUtils.format(AutoConstants.GET_REGISTRY_256, server.getIp(), admDockerRegistry.getPort(), imageName, tag);
            //System.out.println(getSh256);
            String exec = remoteSshUtil.exec(getSh256, session);
            String[] split = exec.split("\r\n");
            String code = split[0];
            if (code.contains("200")) {
                String sh256 = split[3];
                sh256 = sh256.replace("Docker-Content-Digest: ", "");
                //System.out.println(sh256);
                //执行del
                String s1 = StringUtils.format(AutoConstants.DEL_REGISTRY, server.getIp(), admDockerRegistry.getPort(), imageName, sh256);
                remoteSshUtil.exec(s1, session);
                //System.out.println(s1);
                //gc
                remoteSshUtil.exec(AutoConstants.GARBAGE_COLLECTION, session);
                //System.out.println(AutoConstants.GARBAGE_COLLECTION);
            } else if (code.contains("404")) {

            } else {
                System.out.println(exec);
            }
            admDockerRegistryService.restartRegistry(admDockerRegistry.getId());
            Thread.sleep(3 * 1000);
        } catch (Exception e) {
            log.error(e.getMessage());
        } finally {
            remoteSshUtil.close(session);
        }
    }


    /**
     * @param tag        标签
     * @param branch     分支
     * @param admProject adm项目
     * @description: 打待上线镜像
     * @author: dongshoushan
     * @date:2022-11-23 21:34:26
     */
    @Override
    public void imageToRegistry(String tag, String branch, AdmProject admProject, List<AdmDockerDeploy> admDockerDeployList, AdmProjectAutoConfig autoConfig) {
        Session session = null;
        try {
            //只构建编译推仓库
            Long projectId = admProject.getId();
            System.out.println("项目：" + JacksonUtils.toString(admProject));
            AdmProjectAutoConfig devConfig = admProjectAutoConfigMapper.getByDevConfig(projectId);
            Long namespaceId = autoConfig.getNamespaceId();
            AdmNamespace admNamespace = admNamespaceMapper.selectById(namespaceId);
            Long registryId = admNamespace.getRegistryId();
            Server server = serverService.getServerByRegistryId(registryId);
            AdmDockerRegistry admDockerRegistry = admDockerRegistryMapper.selectById(admNamespace.getRegistryId());
            //仓库所在docker
            AdmDocker registryDocker = admDockerService.getByIp(server.getIp());
            session = remoteSshUtil.connect(server);
            //先清理之前的镜像包
            remoteSshUtil.exec(StringUtils.format("mkdir -p /data/{}", admProject.getProjectName()), session);
            remoteSshUtil.exec(StringUtils.format("rm -rf /data/{}/*", admProject.getProjectName()), session);
            for (AdmDockerDeploy dockerDeploy : admDockerDeployList) {
                //上传
                dockerDeploy.setLocalFile(dockerDeploy.getLocalFile().replaceFirst(devConfig.getBranch(), branch));
                dockerDeploy.setTag(tag);

                Map map = new HashMap<String, Object>(16);
                String localFile = dockerDeploy.getLocalFile();
                String temp;
                if (localFile.contains("\\")) {
                    temp = "\\\\";
                } else {
                    temp = "/";
                }
                String[] split = localFile.split(temp);
                String jarName = split[split.length - 1];
                map.put("jarName", jarName);
                List<JdkVersionDto> jdkVersionList = AutoConstants.JDK_VERSION_LIST;
                String jdkVersion = dockerDeploy.getJdkVersion();
                JdkVersionDto jdkVersionDto = jdkVersionList.stream().filter(s -> s.getKey().equals(jdkVersion)).findFirst().get();
                map.put("jdkVersion", jdkVersionDto.getValue());
                if (jdkVersionDto.getVersion() >= 17) {
                    map.put("enablePreview", "--enable-preview");
                } else {
                    map.put("enablePreview", "");
                }
                map.put("env", "");
                if (StringUtils.isNotEmpty(dockerDeploy.getEnvs())) {
                    List<EnvDto> envDtoList = JacksonUtils.toList(dockerDeploy.getEnvs(), EnvDto.class);
                    if (StringUtils.isNotEmpty(envDtoList)) {
                        // 拼接环境变量
                        String envString = envDtoList.stream()
                                .map(env -> {
                                    if (StringUtils.isNotEmpty(env.getValue())) {
                                        return StringUtils.format("\"{}={}\"", env.getKey(), env.getValue());
                                    } else {
                                        return StringUtils.format("\"{}\"", env.getKey());
                                    }
                                })
                                .collect(Collectors.joining(", "));
                        map.put("env", envString + ",");
                    }
                }
                System.out.println(StringUtils.format("上传jar包：{}到目标ip：{}，目录：{},请稍后...", dockerDeploy.getLocalFile(), server.getIp(), dockerDeploy.getRemoteTargetDirectory()));
                remoteSshUtil.putFile(session, dockerDeploy.getLocalFile(), dockerDeploy.getRemoteTargetDirectory());
                String fileLocalPath = AutoConstants.baseLocalPath + dockerDeploy.getId() + "/Dockerfile";
                FileUtils.generateFileByTemplate("Dockerfile.ftl", fileLocalPath, AutoConstants.baseLocalPath + dockerDeploy.getId(), map);
                remoteSshUtil.putFile(session, fileLocalPath, dockerDeploy.getRemoteTargetDirectory());

                DockerClient registryDockerClient = dockerUtil.getDockerClientByDocker(SpringUtils.getBean(AdmDockerServiceImpl.class).convertToVo(registryDocker));
                String imageName = StringUtils.format("{}:{}/{}:{}", server.getIp(), admDockerRegistry.getPort(), dockerDeploy.getModuleName(), tag);
                //docker镜像构建
                dockerUtil.delContainer(registryDockerClient, dockerDeploy.getModuleName());
                dockerUtil.delImageByName(registryDockerClient, dockerDeploy.getModuleName());
                delRegistry(server, admDockerRegistry, dockerDeploy.getModuleName(), tag);
                String command = StringUtils.format("cd {} && docker build -t {}:{}/{}:{} .", dockerDeploy.getRemoteTargetDirectory(), server.getIp(), admDockerRegistry.getPort(),
                        dockerDeploy.getModuleName(), dockerDeploy.getTag());
                System.out.println(command);
                remoteSshUtil.exec(command, session);
                //记录历史
                dockerDeployHst(dockerDeploy, admNamespace.getRegistryId(), namespaceId);
                remoteSshUtil.exec(StringUtils.format("docker push {}", imageName), session);
                //删除多余历史版本，只保留最近的几个版本
                delHstTag(dockerDeploy.getModuleName(), admNamespace.getRegistryId());
                dockerUtil.close(registryDockerClient);
                System.out.println(StringUtils.format("【{}】镜像：{} 已存储到仓库：{}", branch, imageName, server.getIp()));
                //执行docker save -o命令打包到虚拟机本地
                remoteSshUtil.exec(StringUtils.format("docker save -o /data/{}/{}.tar {}:{}/{}:{}", admProject.getProjectName(), dockerDeploy.getModuleName(),
                        server.getIp(), admDockerRegistry.getPort(), dockerDeploy.getModuleName(), dockerDeploy.getTag()), session);
            }
        } catch (Exception e) {
            throw new ServiceException(e.getMessage());
        } finally {
            remoteSshUtil.close(session);
        }

    }

    /**
     * 上传镜像到生产
     *
     * @param tag        标签
     * @param projectId  项目id
     * @param registryId 注册表id
     * @throws Exception 异常
     */
    @Override
    public void uploadImagesToProd(String tag, Long projectId, Long registryId, List<String> moduleNameList) throws Exception {
        //把待上线镜像拷贝到生产环境
        if (dssProperties.getIsConnectToProd()) {
            LambdaQueryWrapper<AdmRegistryTagHst> lambdaQuery = Wrappers.lambdaQuery(AdmRegistryTagHst.class);
            lambdaQuery.eq(AdmRegistryTagHst::getProjectId, projectId).in(AdmRegistryTagHst::getImageName, moduleNameList)
                    .eq(AdmRegistryTagHst::getRegistryId, registryId).eq(AdmRegistryTagHst::getTag, tag);
            List<AdmRegistryTagHst> tagHstList = admRegistryTagHstMapper.selectList(lambdaQuery);
            List<Long> collect = tagHstList.stream().map(AdmRegistryTagHst::getId).collect(Collectors.toList());
            List<String> stringList = collect.stream().map(Object::toString).collect(Collectors.toList());
            //导出到本地
            admRegistryTagHstService.exportImages(stringList);
            for (AdmRegistryTagHst admRegistryTagHst : tagHstList) {
                List<AdmDockerDeploy> admDockerDeploys = admDockerDeployMapper.selectList(Wrappers.lambdaQuery(AdmDockerDeploy.class)
                        .eq(AdmDockerDeploy::getProjectId, admRegistryTagHst.getProjectId()));
                List<Long> spaceId = admDockerDeploys.stream().map(AdmDockerDeploy::getNamespaceId).collect(Collectors.toList());
                List<AdmNamespace> admNamespaces = admNamespaceMapper.selectBatchIds(spaceId);
                String fileName = StringUtils.format("{}.{}.tar", admRegistryTagHst.getImageName(), tag);
                AdmNamespace admNamespace = admNamespaces.stream().filter(s -> s.getName().contains(dssProperties.getProdNameSpaceKey())).findFirst().orElse(null);
                if (admNamespace == null) {
                    throw new ServiceException("请先配置此项目的生产模块。其中命名空间必须包含关键字：" + dssProperties.getProdNameSpaceKey());
                }
                //上传镜像
                admRegistryTagHstService.importJarImages(projectId, admNamespace.getId(), FileUtils.getMultipartFile(AutoConstants.DOCKER_DOWNLOAD_TEMP_PATH + "/" + fileName));
            }
        }
    }

    @Override
    public void changeStatus(AdmDockerDeployUpdateDto updateDto) {
        AdmDockerDeploy admDockerDeploy = BeanUtils.copy(updateDto, AdmDockerDeploy.class);
        int number = admDockerDeployMapper.updateById(admDockerDeploy);
        if (number == 1) {
            log.info("修改成功{}", JacksonUtils.toString(admDockerDeploy));
        }
    }

    @Override
    public Boolean buildMaster(String maven) throws IOException {
        Process process = Runtime.getRuntime().exec(maven);
        InputStream is = process.getInputStream();
        String s;
        LineNumberReader lnr = new LineNumberReader(new InputStreamReader(is, "gbk"));
        Boolean flag = false;
        long start = System.currentTimeMillis();
        while ((s = lnr.readLine()) != null) {
            System.out.println(s);
            if (s.contains("BUILD") && s.contains("SUCCESS")) {
                System.out.println("当前状态：构建成功");
                flag = true;
                break;
            }
            if (((System.currentTimeMillis() - start) / (1000 * 60) > dssProperties.getBuildOutOfTime())) {
                flag = false;
                System.out.println("当前状态：构建超时");
                break;
            }
        }
        lnr.close();
        if (!flag) {
            log.error("构建失败");
        }
        return flag;
    }

    @Override
    public void restartServiceByIpAndServer(String ip, String module) throws IOException {
        AdmDocker admDocker = admDockerService.getByIp(ip);
        AdmDockerDeploy dockerDeploy = this.getOne(Wrappers.lambdaQuery(AdmDockerDeploy.class).eq(AdmDockerDeploy::getModuleName, module).eq(AdmDockerDeploy::getDockerId, admDocker.getId()));
        restartService(dockerDeploy.getId().toString());
    }


    /**
     * 拉取并启动新容器
     *
     * @param admDockerDeploy
     * @param imageName
     */
    @Override
    public void pullAndStart(AdmDockerDeploy admDockerDeploy, String imageName) {
        //部署宿主机docker
        AdmDocker admDocker = admDockerMapper.selectById(admDockerDeploy.getDockerId());
        List<AdmDocker> dockers = new ArrayList<>();
        dockers.add(admDocker);
        List<AdmDockerVo> admDockers = admDockerService.convertToVo(dockers);
        DockerClient dockerClient = dockerUtil.getDockerClientByDocker(admDockers.get(0));
        pullAndStart(dockerClient, admDockerDeploy, imageName);
    }

    /**
     * 拉取镜像并启动
     *
     * @param dockerClient
     * @param admDockerDeploy
     * @param imageFullName
     */
    public void pullAndStart(DockerClient dockerClient, AdmDockerDeploy admDockerDeploy, String imageFullName) {
        //先删除再重新拉
        Session session = null;
        try {
            if (StringUtils.isNotBlank(admDockerDeploy.getContainerId())) {
                dockerUtil.delContainerById(dockerClient, admDockerDeploy.getContainerId());
            }
            dockerUtil.delContainer(dockerClient, admDockerDeploy.getModuleName());
            dockerUtil.delImageByName(dockerClient, admDockerDeploy.getModuleName());
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        try {
            //pullImageAndStart(dockerClient, admDockerDeploy, imageFullName);
            String info = StringUtils.format("{} {}开始拉取ing：", DateUtil.now(), admDockerDeploy.getModuleName());
            FileUtils.writeDockerFileInRealTime(info);
            FileUtils.writeDockerFileByPath(admDockerDeploy, info);
            AdmDocker admDocker = admDockerMapper.selectById(admDockerDeploy.getDockerId());
            session = remoteSshUtil.connect(admDocker);
            String pullCmd = StringUtils.format("docker pull {}", imageFullName);
            remoteSshUtil.exec(pullCmd, session);
            FileUtils.writeDockerFileInRealTime(StringUtils.format("执行 {}", pullCmd));
            FileUtils.writeDockerFileByPath(admDockerDeploy, StringUtils.format("执行 {}", pullCmd));
            long start = System.currentTimeMillis();
            while (true) {
                Image image = dockerUtil.getImageNameByName(dockerClient, imageFullName);
                if (image != null) {
                    break;
                }
                long pullTime = System.currentTimeMillis() - start;
                if (pullTime > 3000) {
                    System.out.println(StringUtils.format("执行拉取已耗时：{}毫秒，再次执行：{}", pullTime, pullCmd));
                    remoteSshUtil.exec(pullCmd, session);
                }
                if (pullTime > 1000 * 60) {
                    MyEmail email = MyEmail.builder().text(StringUtils.format("拉取镜像超时")).subject(StringUtils.format("超时镜像命令：{}", pullCmd)).receiver("dongss5@lenovo.com").build();
                    mailUtil.sendMail(email);
                    throw new ServiceException("拉取镜像超时:" + pullCmd);
                }
                Thread.sleep(3000);
            }
            createAndStartContainer(admDockerDeploy, imageFullName, dockerClient);
        } catch (Exception e) {
            e.getMessage();
        } finally {
            remoteSshUtil.close(session);
        }
    }

    private void pullImageAndStart(DockerClient dockerClient, AdmDockerDeploy admDockerDeploy, String imageFullName) {
        dockerClient.pullImageCmd(imageFullName).exec(new ResultCallback<PullResponseItem>() {
            @Override
            public void onStart(Closeable closeable) {
                String info = StringUtils.format("{} {}开始拉取ing：", DateUtil.now(), admDockerDeploy.getModuleName());
                try {
                    FileUtils.writeDockerFileInRealTime(info);
                    FileUtils.writeDockerFileByPath(admDockerDeploy, info);
                    System.out.println(info);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }

            @Override
            public void onNext(PullResponseItem pullResponseItem) {
                if (StringUtils.isNotEmpty(pullResponseItem.getProgress())) {
                    String info = pullResponseItem.getStatus() + "" + pullResponseItem.getProgress();
                    try {
                        FileUtils.writeDockerFileByPath(admDockerDeploy, info);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                    System.out.println(pullResponseItem.getStatus() + "" + pullResponseItem.getProgress());
                }
            }

            @Override
            public void onError(Throwable throwable) {
                throwable.printStackTrace();
            }

            @Override
            public void onComplete() {
                createAndStartContainer(admDockerDeploy, imageFullName, dockerClient);
            }

            @Override
            public void close() {
                System.out.println("拉取关闭");
            }
        });
    }

    private void createAndStartContainer(AdmDockerDeploy admDockerDeploy, String imageFullName, DockerClient dockerClient) {
        try {
            admDockerDeploy.setDeployStatus(DockerDeployStatusEnum.PULL.getCode());
            admDockerDeployMapper.updateById(admDockerDeploy);
            String info = StringUtils.format("{} 拉取镜像完成:{}", DateUtil.now(), imageFullName);
            FileUtils.writeDockerFileInRealTime(info);
            FileUtils.writeDockerFileByPath(admDockerDeploy, info);
            reloadHtml();
            AdmDocker admDocker = admDockerMapper.selectById(admDockerDeploy.getDockerId());

            CreateContainerResponse container = createContainer(dockerClient, admDockerDeploy, admDocker, imageFullName);
            String info2 = StringUtils.format("{} 开始创建新容器:{}", DateUtil.now(), imageFullName);
            FileUtils.writeDockerFileInRealTime(info2);
            FileUtils.writeDockerFileByPath(admDockerDeploy, info2);
            reloadHtml();
            admDockerDeploy.setDeployStatus(DockerDeployStatusEnum.START_NEW_CONTAINER.getCode());
            admDockerDeploy.setContainerId(container.getId());
            admDockerDeployMapper.updateById(admDockerDeploy);
            dockerClient.startContainerCmd(container.getId()).exec();
            List<Container> collect = dockerClient.listContainersCmd().withShowAll(true).exec().stream().filter(containerNew -> containerNew.getId().equals(container.getId())).collect(Collectors.toList());
            Container c = collect.get(0);
            while (true) {
                if ("running".equals(c.getState())) {
                    admDockerDeploy.setDeployStatus(DockerDeployStatusEnum.START_SUCCESS.getCode());
                    admDockerDeploy.setLastDeployDate(new Date());
                    admDockerDeployMapper.updateById(admDockerDeploy);
                    String info3 = StringUtils.format("{} INFO启动容器成功:{}", DateUtil.now(), imageFullName);
                    FileUtils.writeDockerFileInRealTime(info3);
                    FileUtils.writeDockerFileByPath(admDockerDeploy, info3);
                    alertSuccessMsg(StringUtils.format("启动容器成功:{}", admDockerDeploy.getModuleName()));
                    break;
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
            //部署宿主机
            //部署宿主机docker
            AdmDocker admDocker = admDockerMapper.selectById(admDockerDeploy.getDockerId());
            Server dockerServer = serverService.getServerById(admDocker.getServerId());
            deployError(admDockerDeploy, e.getMessage(), dockerServer);

        } finally {
            //try {
            //    dockerClient.close();
            //} catch (IOException e) {
            //    throw new RuntimeException(e);
            //}
        }
    }

    /**
     * 创建容器
     *
     * @param dockerClient
     */
    public CreateContainerResponse createContainer(DockerClient dockerClient, AdmDockerDeploy admDockerDeploy, AdmDocker admDocker, String imageFullName) {
        try {
            Server server = serverService.getServerByDockerId(admDockerDeploy.getDockerId());
            String hostId = admDocker.getHostId();
            //创建容器、启动容器
            //端口绑定  宿主机端口 -> 容器端口  不等长参数，可绑定多个暴露端口
            HostConfig hostConfig = HostConfig.newHostConfig();
            List<PortBinding> bindings = new ArrayList<>();
            List<ExposedPort> exposedPorts = new ArrayList<>();
            hostConfig.withNetworkMode("host");
            //if (StringUtils.isNotEmpty(portBinding)){
            //    String[] split = portBinding.split(",");
            //    for (String string : split) {
            //        PortBinding binding = PortBinding.parse(string);
            //        bindings.add(binding);
            //        String[] parts = string.split(":");
            //        exposedPorts.add(ExposedPort.tcp(Integer.parseInt(parts[1])));
            //    }
            //    hostConfig.withPortBindings(bindings);
            //}
            List<Bind> list = new ArrayList<>();
            //项目应用日志挂载
            list.add(Bind.parse("/data/docker/app/logs:/data/docker/app/logs"));
            //业务日志挂载
            list.add(Bind.parse("/data/docker/logs:/data/docker/logs"));
            String mountThePath = admDockerDeploy.getMountThePath();
            //挂载路径
            if (StringUtils.isNotEmpty(mountThePath)) {
                String[] split1 = mountThePath.split(",");
                for (String s : split1) {
                    list.add(Bind.parse(s));
                }
            }
            hostConfig.withBinds(list);
            if (StringUtils.isNotEmpty(hostId)) {
                String[] hostIdArray = hostId.split(",");
                List<AdmHosts> admHosts = admHostsMapper.selectBatchIds(Arrays.asList(hostIdArray));
                String[] array = admHosts.stream().map(admHost -> admHost.getHostName() + ":" + admHost.getIp()).toArray(String[]::new);
                hostConfig.withExtraHosts(array);
            }
            RestartPolicy restartPolicy = RestartPolicy.alwaysRestart();
            hostConfig.withRestartPolicy(restartPolicy);
            //环境设置
            List<String> env = new ArrayList<>();
            env.add("SPRING_PROFILES_ACTIVE=" + admDockerDeploy.getSpringProfilesActive());
            Long nacosId = admDockerDeploy.getNacosId();
            if (nacosId != null) {
                AdmNacos admNacos = admNacosMapper.selectById(nacosId);
                String nacosAddr = StringUtils.format("{}:{}", serverService.getServerByDockerId(admNacos.getDockerId()).getIp(), admNacos.getNacosPort());
                env.add("spring.cloud.nacos.server-addr=" + nacosAddr);
                env.add("spring.cloud.nacos.config.username=" + admNacos.getNacosUsername());
                env.add("spring.cloud.nacos.config.password=" + admNacos.getNacosPassword());
                env.add("spring.cloud.nacos.discovery.username=" + admNacos.getNacosUsername());
                env.add("spring.cloud.nacos.discovery.password=" + admNacos.getNacosPassword());
                env.add("DUBBO_IP_TO_REGISTRY=" + server.getIp());
            }
            if (bindings.isEmpty()) {
                CreateContainerResponse container = dockerClient.createContainerCmd(imageFullName)
                        .withName(admDockerDeploy.getModuleName())
                        .withHostConfig(hostConfig)
                        .withEnv(env)
                        .exec();
                return container;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;

    }

    @Override
    public void versionUpdate(VersionUpdateDto dto) throws IOException {
        init();
        AdmRegistryTagHst admRegistryTagHst = admRegistryTagHstMapper.selectById(dto.getTagHstId());
        List<Long> dockerDeployIds = dto.getDockerDeployIds();
        List<AdmDockerDeploy> deployList;
        //不传节点id默认更新所有
        if (CollectionUtil.isEmpty(dockerDeployIds)) {
            AdmNamespace admNamespace = admNamespaceService.getById(admRegistryTagHst.getNamespaceId());
            LambdaQueryWrapper<AdmDockerDeploy> query = Wrappers.lambdaQuery(AdmDockerDeploy.class);
            query.eq(AdmDockerDeploy::getProjectId, admRegistryTagHst.getProjectId()).eq(AdmDockerDeploy::getNamespaceId, admNamespace.getId())
                    .eq(AdmDockerDeploy::getModuleName, admRegistryTagHst.getImageName());
            deployList = admDockerDeployMapper.selectList(query);
        } else {
            deployList = admDockerDeployMapper.selectBatchIds(dockerDeployIds);
        }
        if (deployList == null) {
            return;
        }
        for (int i = 0; i < deployList.size(); i++) {
            AdmDockerDeploy admDockerDeploy = deployList.get(i);
            List<AdmDockerDeploy> list = new ArrayList<>();
            list.add(admDockerDeploy);
            FileUtils.recreateDockerFileByPath(list);
            admDockerDeploy.setTag(admRegistryTagHst.getTag());
            admDockerDeployMapper.updateById(admDockerDeploy);
            AdmNamespace admNamespace = admNamespaceMapper.selectById(admDockerDeploy.getNamespaceId());
            AdmDockerRegistry admDockerRegistry = admDockerRegistryMapper.selectById(admNamespace.getRegistryId());
            //仓库虚拟机
            Server registryServer = serverService.getServerById(admDockerRegistry.getServerId());
            String imageName = StringUtils.format("{}:{}/{}:{}", registryServer.getIp(), admDockerRegistry.getPort(), admDockerDeploy.getModuleName(), admDockerDeploy.getTag());
            pullAndStart(admDockerDeploy, imageName);
            try {
                if (i < deployList.size() - 1) {
                    Thread.sleep(dssProperties.getRestartInterval());
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    @Override
    public void jobToDeploy(Long projectId, Long namespaceId) throws IOException {
        LambdaQueryWrapper<AdmNamespace> query = Wrappers.lambdaQuery(AdmNamespace.class);
        query.eq(AdmNamespace::getId, namespaceId);
        AdmNamespace admNamespace = admNamespaceMapper.selectOne(query);
        Long registryId = admNamespace.getRegistryId();
        AdmProject admProject = admProjectMapper.selectById(projectId);
        //查询开启部署的模块
        LambdaQueryWrapper<AdmDockerDeploy> lambdaQuery = Wrappers.lambdaQuery(AdmDockerDeploy.class);
        lambdaQuery.eq(AdmDockerDeploy::getProjectId, projectId).eq(AdmDockerDeploy::getType, 0).eq(AdmDockerDeploy::getNamespaceId, namespaceId)
                .eq(AdmDockerDeploy::getEnable, 0);
        List<AdmDockerDeploy> dockerDeployList = admDockerDeployMapper.selectList(lambdaQuery);
        List<String> names = dockerDeployList.stream().map(AdmDockerDeploy::getModuleName).collect(Collectors.toList());

        LambdaQueryWrapper<AdmRegistryTagHst> registryTagHstWrapper = Wrappers.lambdaQuery(AdmRegistryTagHst.class);
        registryTagHstWrapper.eq(AdmRegistryTagHst::getRegistryId, registryId).eq(AdmRegistryTagHst::getProjectId, projectId)
                .in(AdmRegistryTagHst::getImageName, names).groupBy(AdmRegistryTagHst::getImageName);
        List<AdmRegistryTagHst> registryTagHstList = admRegistryTagHstMapper.selectList(registryTagHstWrapper);
        //查询最新版本
        registryTagHstList.stream().<Runnable>map(registryTagHst -> () -> {
            LambdaQueryWrapper<AdmRegistryTagHst> registryTagHstWrapper2 = Wrappers.lambdaQuery(AdmRegistryTagHst.class);
            registryTagHstWrapper2.eq(AdmRegistryTagHst::getRegistryId, registryId)
                    .eq(AdmRegistryTagHst::getProjectId, projectId)
                    .eq(AdmRegistryTagHst::getImageName, registryTagHst.getImageName()).orderByDesc(AdmRegistryTagHst::getCreateTime).last("limit 1");
            AdmRegistryTagHst tagHst = admRegistryTagHstMapper.selectOne(registryTagHstWrapper2);
            if (tagHst != null) {
                VersionUpdateDto updateDto = VersionUpdateDto.builder().tagHstId(tagHst.getId()).build();
                System.out.println(StringUtils.format("后端开始更新,项目id:{},项目名称:{},命名空间:{},模块名称:{},版本:{}", admProject.getId(), admProject.getProjectName(), admNamespace.getName(), tagHst.getImageName(), tagHst.getTag()));
                try {
                    versionUpdate(updateDto);
                } catch (IOException e) {
                    throw new ServiceException(e.getMessage());
                }
            } else {
                System.out.println(StringUtils.format("无版本记录,项目id:{},项目名称:{},命名空间:{},模块名称:{}", projectId, admProject.getProjectName(), admNamespace.getName(), tagHst.getImageName()));
            }
        }).forEach(threadPoolTaskExecutor::execute);

    }

    @Override
    public List<AdmDockerDeployVo> getSuccess() throws InterruptedException {
        List<AdmDockerDeploy> selectList = admDockerDeployMapper.selectList(Wrappers.lambdaQuery(AdmDockerDeploy.class)
                .eq(AdmDockerDeploy::getDeployStatus, DockerDeployStatusEnum.BUILD_IMAGE.getCode())
                .ne(AdmDockerDeploy::getDeployStatus, DockerDeployStatusEnum.MAVEN_FAILED.getCode())
        );
        return convertToVo(selectList);
    }

    @Override
    public void restartService(String ids) throws IOException {
        init();
        String[] split = ids.split(",");
        List<String> strings = Arrays.asList(split);
        List<AdmDockerDeploy> deployList = admDockerDeployMapper.selectBatchIds(strings);
        for (AdmDockerDeploy deploy : deployList) {
            AdmDocker admDocker = admDockerMapper.selectById(deploy.getDockerId());
            DockerClient dockerClient = dockerUtil.getDockerClientByDocker(SpringUtils.getBean(AdmDockerServiceImpl.class).convertToVo(admDocker));
            dockerClient.restartContainerCmd(deploy.getContainerId()).exec();
            dockerUtil.close(dockerClient);
            log.info("重启成功:{}", JacksonUtils.toString(deploy));
        }
    }

    @Override
    public void stopService(String ids) {
        String[] split = ids.split(",");
        List<String> strings = Arrays.asList(split);
        List<AdmDockerDeploy> deployList = admDockerDeployMapper.selectBatchIds(strings);
        for (AdmDockerDeploy dockerDeploy : deployList) {
            AdmDocker admDocker = admDockerMapper.selectById(dockerDeploy.getDockerId());
            DockerClient dockerClient = dockerUtil.getDockerClientByDocker(SpringUtils.getBean(AdmDockerServiceImpl.class).convertToVo(admDocker));
            dockerClient.stopContainerCmd(dockerDeploy.getContainerId()).exec();
            dockerUtil.close(dockerClient);
            log.info("停止成功:{}", JacksonUtils.toString(dockerDeploy));
        }
    }

    @Override
    public void pauseService(String ids) {
        String[] split = ids.split(",");
        List<String> strings = Arrays.asList(split);
        List<AdmDockerDeploy> deployList = admDockerDeployMapper.selectBatchIds(strings);
        for (AdmDockerDeploy dockerDeploy : deployList) {
            AdmDocker admDocker = admDockerMapper.selectById(dockerDeploy.getDockerId());
            DockerClient dockerClient = dockerUtil.getDockerClientByDocker(SpringUtils.getBean(AdmDockerServiceImpl.class).convertToVo(admDocker));
            dockerClient.pauseContainerCmd(dockerDeploy.getContainerId()).exec();
            dockerUtil.close(dockerClient);
            log.info("暂停成功:{}", JacksonUtils.toString(dockerDeploy));
        }
    }

    @Override
    public void init() throws IOException {
        remoteSshUtil.recreateDockerFile();
        List<AdmDockerDeploy> list = list(new QueryWrapper<>());
        list.forEach(AdmDockerDeploy -> {
            AdmDockerDeploy.setDeployStatus(DockerDeployStatusEnum.INIT.getCode());
            AdmDockerDeploy.setSpeed("");
            AdmDockerDeploy.setTransfered("");
            AdmDockerDeploy.setSpeedOfProgress("");
            AdmDockerDeploy.setFileSize("");
        });
        updateBatchById(list);
    }

    @Override
    public List<AllDockerInfoVo> getAllDockerInfo(AllDockerInfoDto dto) throws InterruptedException {
        List<AllDockerInfoVo> list = admDockerDeployMapper.getAllDockerInfo(dto);
        List<AdmDockerDeploy> admDockerDeploys = admDockerDeployMapper.selectList(Wrappers.lambdaQuery(AdmDockerDeploy.class)
                .eq(AdmDockerDeploy::getProjectId, dto.getProjectId())
                .eq(AdmDockerDeploy::getNamespaceId, dto.getNamespaceId()));
        List<AdmRegistryTagHst> registryTagHsts = admRegistryTagHstMapper.selectList(Wrappers.lambdaQuery(AdmRegistryTagHst.class)
                .eq(AdmRegistryTagHst::getProjectId, dto.getProjectId())
                .eq(AdmRegistryTagHst::getNamespaceId, dto.getNamespaceId())
                .orderByDesc(AdmRegistryTagHst::getCreateTime));
        List<Long> dockerIds = admDockerDeploys.stream().map(AdmDockerDeploy::getDockerId).distinct().collect(Collectors.toList());
        List<AdmDocker> dockerList = SpringUtils.getBean(AdmDockerServiceImpl.class).getAll()
                .stream().filter(s->dockerIds.contains(s.getId())).collect(Collectors.toList());
        Map<String, List<Container>> containerMap = admDockerService.getContainerMap(dockerList);
        list.forEach(allDockerInfoVo -> {
            //节点数统计
            List<AdmDockerDeploy> deployList = admDockerDeploys.stream().filter(s -> allDockerInfoVo.getModuleName().equals(s.getModuleName())).collect(Collectors.toList());
            List<AdmDockerDeployVo> voList = BeanUtils.copyList(deployList, AdmDockerDeployVo.class);
            voList.forEach(vo -> {
                List<Container> containers = containerMap.get("AdmDockerVo" + vo.getDockerId());
                Container container = containers.stream().filter(s -> s.getId().equals(vo.getContainerId())).findFirst().orElse(null);
                if (container == null) {
                    vo.setContainerStatusName("容器未创建");
                } else {
                    vo.setContainerStatusName(container.getState());
                }
            });
            allDockerInfoVo.setAllNode(deployList.size());
            long count = voList.stream().filter(admDockerDeployVo -> "running".equals(admDockerDeployVo.getContainerStatusName())).count();
            allDockerInfoVo.setRunNode(count);
            List<AdmRegistryTagHst> registryTagHstList = registryTagHsts.stream().filter(s -> allDockerInfoVo.getModuleName().equals(s.getImageName())).collect(Collectors.toList());
            //版本记录
            if (CollectionUtil.isEmpty(registryTagHstList)) {
                allDockerInfoVo.setDescription(StringUtils.format("<span style=\"color: red\">当前仓库无版本记录，请先上传镜像</span>"));
                return;
            }
            List<String> tags = registryTagHstList.stream().map(AdmRegistryTagHst::getTag).collect(Collectors.toList());
            allDockerInfoVo.setTags(tags);
            AdmRegistryTagHst admRegistryTagHst = registryTagHstList.get(0);
            String newTag = admRegistryTagHst.getTag();
            long newCount = voList.stream().filter(admDockerDeployVo -> "running".equals(admDockerDeployVo.getContainerStatusName()) && newTag.equals(admDockerDeployVo.getTag())).count();
            String color = newCount == deployList.size() ? "green" : "red";
            allDockerInfoVo.setDescription(StringUtils.format("最新tag{} 当前<span style=\"color: {}\">{}</span>个节点运行最新tag", newTag, color, newCount));
        });
        return list;
    }

    @Override
    public void updateTag(UpdateDockerTagDto updateDto) {
        String ids = updateDto.getIds();
        String[] split = ids.split(",");
        List<AdmDockerDeploy> list = admDockerDeployMapper.selectBatchIds(Arrays.asList(split));
        for (AdmDockerDeploy admDockerDeploy : list) {
            if (StringUtils.isEmpty(updateDto.getTag()) && StringUtils.isEmpty(admDockerDeploy.getTag())) {
                throw new ServiceException("请先设置项目模块版本号");
            }
            if (StringUtils.isNotEmpty(updateDto.getTag())) {
                admDockerDeploy.setTag(updateDto.getTag());
            }
            if (StringUtils.isEmpty(admDockerDeploy.getRemoteTargetDirectory())) {
                throw new ServiceException("请先设置构建镜像目标位置");
            }
            if (StringUtils.isEmpty(admDockerDeploy.getLocalFile())) {
                throw new ServiceException("请先设置本地开发jar包位置");
            }
        }
        this.updateBatchById(list);
    }


    /**
     * maven编译
     *
     * @param maven
     * @param list
     * @return
     */
    @Override
    public Boolean mavenBuild(String maven, List<AdmDockerDeploy> list) {
        Boolean flag = false;
        try {
            FileUtils.writeDockerFileInRealTime(StringUtils.format("{} 开始进行maven编译项目，编译详情可点击表格日志。。。。。。", DateUtil.now()));
            AdmDockerDeploy dockerDeploy = list.get(0);
            reloadHtml();
            long start = System.currentTimeMillis();
            //重新生成日志
            FileUtils.recreateDockerFileByPath(list);
            FileUtils.writeDockerAllLog(list, StringUtils.format("{} 开始maven构建jar包中,请稍等片刻", DateUtil.now()));
            list.forEach(deploy -> {
                deploy.setDeployStatus(DockerDeployStatusEnum.BUILDING.getCode());
                deploy.setLastDeployDate(new Date());
            });
            updateBatchById(list);
            reloadHtml();
            Process p;
            p = Runtime.getRuntime().exec(maven);
            InputStream is = p.getInputStream();
            String s;
            LineNumberReader lnr = new LineNumberReader(new InputStreamReader(is, "gbk"));
            while ((s = lnr.readLine()) != null) {
                FileUtils.writeDockerAllLog(list, s);
                if (s.contains("BUILD") && s.contains("SUCCESS")) {
                    list.forEach(deploy -> {
                        deploy.setDeployStatus(DockerDeployStatusEnum.MAVEN_SUCCESS.getCode());
                        deploy.setLastDeployDate(new Date());
                    });
                    updateBatchById(list);
                    String infoAllSuccess = StringUtils.format("{} maven编译完成", DateUtil.now());
                    FileUtils.writeDockerFileInRealTime(infoAllSuccess);
                    reloadHtml();
                    log.info(infoAllSuccess);
                    flag = true;
                    break;
                }
                if (s.contains("FAILURE")) {
                    flag = false;
                    list.forEach(deploy -> {
                        deploy.setDeployStatus(DockerDeployStatusEnum.MAVEN_FAILED.getCode());
                        deploy.setLastDeployDate(new Date());
                    });
                    updateBatchById(list);
                    String info = StringUtils.format("{} ERROR 项目:{},maven构建失败,构建命令{},耗时：{}秒", DateUtil.now(), dockerDeploy.getModuleName(), maven, (System.currentTimeMillis() - start) / 1000);
                    FileUtils.writeDockerAllLog(list, info);
                    FileUtils.writeDockerFileInRealTime(info);
                    log.error(info);
                    alertFailMsg("当前状态：构建失败");
                    break;
                }
                if (((System.currentTimeMillis() - start) / (1000 * 60) > dssProperties.getBuildOutOfTime())) {
                    flag = false;
                    list.forEach(deploy -> {
                        deploy.setDeployStatus(DockerDeployStatusEnum.MAVEN_FAILED.getCode());
                        deploy.setLastDeployDate(new Date());
                    });
                    updateBatchById(list);
                    String info = StringUtils.format("{} ERROR 项目:{},maven构建已超过{}分钟,构建命令{},耗时：{}秒", DateUtil.now(), dockerDeploy.getModuleName(),
                            (System.currentTimeMillis() - start) / (1000 * 60), maven, (System.currentTimeMillis() - start) / 1000);
                    FileUtils.writeDockerAllLog(list, info);
                    FileUtils.writeDockerFileInRealTime(info);
                    log.error(info);
                    alertFailMsg("当前状态：构建超时");
                    break;
                }
            }
            return flag;
        } catch (Exception e) {
            list.forEach(deploy -> {
                deploy.setDeployStatus(DockerDeployStatusEnum.MAVEN_FAILED.getCode());
                deploy.setLastDeployDate(new Date());
            });
            updateBatchById(list);
            log.error("构建失败{}", e.getMessage());
            alertFailMsg("部署完毕,有项目异常");
            return false;
        }
    }

    /**
     * 批量操作同一个项目模块
     *
     * @param dto
     */
    @Override
    public void operation(OperationDto dto) throws InterruptedException {
        String operation = dto.getOperation();
        AdmNamespace admNamespace = admNamespaceMapper.selectById(dto.getNamespaceId());
        List<AdmDockerDeploy> deployList = getAllNodeByProjectIdAndNameSpace(dto.getProjectId(), dto.getNamespaceId(), dto.getModuleName());
        for (int i = 0; i < deployList.size(); i++) {
            AdmDockerDeploy deploy = deployList.get(i);
            AdmDocker admDocker = admDockerMapper.selectById(deploy.getDockerId());
            DockerClient dockerClient = dockerUtil.getDockerClientByDocker(SpringUtils.getBean(AdmDockerServiceImpl.class).convertToVo(admDocker));
            if (StringUtils.isNotEmpty(deploy.getContainerId())) {
                List<Container> collect = dockerClient.listContainersCmd().withShowAll(true).exec().stream()
                        .filter(containerNew -> containerNew.getId().equals(deploy.getContainerId())).collect(Collectors.toList());
                if (CollectionUtil.isEmpty(collect)) {
                    deploy.setContainerId("");
                }
            }
            //没有容器 && 有版本记录，则创建容器
            if (StringUtils.isEmpty(deploy.getContainerId()) && StringUtils.isNotEmpty(deploy.getTag())) {
                AdmDockerRegistry admDockerRegistry = admDockerRegistryMapper.selectById(admNamespace.getRegistryId());
                Server registryServer = serverService.getServerById(admDockerRegistry.getServerId());
                String imageFullName = StringUtils.format("{}:{}/{}:{}", registryServer.getIp(), admDockerRegistry.getPort(), deploy.getModuleName(), deploy.getTag());
                CreateContainerResponse response = createContainer(dockerClient, deploy, admDocker, imageFullName);
                deploy.setContainerId(response.getId());
                admDockerDeployMapper.updateById(deploy);
            }
            if (StringUtils.isEmpty(deploy.getContainerId())) {
                throw new ServiceException("容器连接失败无法进行操作，请切换版本尝试");
            }
            switch (operation) {
                case "1":
                    dockerClient.restartContainerCmd(deploy.getContainerId()).exec();
                    log.info("重启成功:{}", JacksonUtils.toString(deploy));
                    if (i < deployList.size() - 1) {
                        Thread.sleep(dssProperties.getRestartInterval());
                    }
                    break;
                case "2":
                    dockerClient.stopContainerCmd(deploy.getContainerId()).exec();
                    log.info("停止成功:{}", JacksonUtils.toString(deploy));
                    break;
                case "3":
                    dockerClient.restartContainerCmd(deploy.getContainerId()).exec();
                    dockerClient.pauseContainerCmd(deploy.getContainerId()).exec();
                    log.info("暂停成功:{}", JacksonUtils.toString(deploy));
                    break;
            }
            dockerUtil.close(dockerClient);
        }
        Thread.sleep(5000);
    }

    private List<AdmDockerDeploy> getAllNodeByProjectIdAndNameSpace(Long projectId, Long namespaceId, String moduleName) {
        QueryWrapper<AdmDockerDeploy> queryWrapper = Wrappers.query();
        queryWrapper.eq("project_id", projectId).eq("namespace_id", namespaceId).eq("module_name", moduleName);
        List<AdmDockerDeploy> list = admDockerDeployMapper.selectList(queryWrapper);
        return list;
    }

    /**
     * 版本批量切换
     *
     * @param dto
     */
    @Override
    public void changeTag(ChangeTagDto dto) throws IOException, InterruptedException {
        AdmNamespace admNamespace = admNamespaceMapper.selectById(dto.getNamespaceId());
        AdmRegistryTagHst admRegistryTagHst = admRegistryTagHstMapper.selectOne(Wrappers.lambdaQuery(AdmRegistryTagHst.class)
                .eq(AdmRegistryTagHst::getProjectId, dto.getProjectId())
                .eq(AdmRegistryTagHst::getRegistryId, admNamespace.getRegistryId())
                .eq(AdmRegistryTagHst::getImageName, dto.getModuleName())
                .eq(AdmRegistryTagHst::getTag, dto.getTag())
                .last("limit 1")
        );
        //更新全部节点的版本
        versionUpdate(VersionUpdateDto.builder().tagHstId(admRegistryTagHst.getId()).build());
        Thread.sleep(5000);
    }

    @Override
    public void addNode(AdmDockerDeployAddDto dto) {
        List<AdmDockerDeploy> list = admDockerDeployMapper.selectList(Wrappers.lambdaQuery(AdmDockerDeploy.class)
                .eq(AdmDockerDeploy::getModuleName, dto.getModuleName())
                .eq(AdmDockerDeploy::getProjectId, dto.getProjectId())
                .eq(AdmDockerDeploy::getNamespaceId, dto.getNamespaceId())
        );
        AdmDockerDeploy admDockerDeploy = list.get(0);
        AdmDockerDeployAddDto addDto = BeanUtils.copy(admDockerDeploy, AdmDockerDeployAddDto.class);
        addDto.setDockerId(dto.getDockerId());
        addDto.setMountThePath(dto.getMountThePath());
        Long id = insert(addDto);
        AdmNamespace admNamespace = admNamespaceMapper.selectById(dto.getNamespaceId());
        List<AdmRegistryTagHst> registryTagHstList = admRegistryTagHstMapper.selectList(Wrappers.lambdaQuery(AdmRegistryTagHst.class)
                .eq(AdmRegistryTagHst::getProjectId, dto.getProjectId())
                .eq(AdmRegistryTagHst::getRegistryId, admNamespace.getRegistryId())
                .eq(AdmRegistryTagHst::getImageName, dto.getModuleName())
                .orderByDesc(AdmRegistryTagHst::getCreateTime)
        );
        if (CollectionUtil.isEmpty(registryTagHstList)) {
            return;
        }
        //创建容器
        AdmRegistryTagHst admRegistryTagHst = registryTagHstList.get(0);
        AdmDockerDeploy deploy = admDockerDeployMapper.selectById(id);
        deploy.setTag(admRegistryTagHst.getTag());
        AdmDockerRegistry admDockerRegistry = admDockerRegistryMapper.selectById(admNamespace.getRegistryId());
        Server registryServer = serverService.getServerById(admDockerRegistry.getServerId());
        String imageFullName = StringUtils.format("{}:{}/{}:{}", registryServer.getIp(), admDockerRegistry.getPort(), deploy.getModuleName(), deploy.getTag());
        pullAndStart(deploy, imageFullName);
    }

    @Override
    public void addModule(AdmDockerDeployAddDto dto) {
        List<AdmDockerDeploy> list = admDockerDeployMapper.selectList(Wrappers.lambdaQuery(AdmDockerDeploy.class)
                .eq(AdmDockerDeploy::getModuleName, dto.getModuleName())
                .eq(AdmDockerDeploy::getProjectId, dto.getProjectId())
                .eq(AdmDockerDeploy::getNamespaceId, dto.getNamespaceId())
        );
        if (CollectionUtil.isNotEmpty(list)) {
            throw new ServiceException("模块已存在，请直接扩容即可");
        }
        AdmDockerDeploy admDockerDeploy = BeanUtils.copy(dto, AdmDockerDeploy.class);
        admDockerDeploy.setDeployStatus(DockerDeployStatusEnum.INIT.getCode());
        check(admDockerDeploy);
        int insert = admDockerDeployMapper.insert(admDockerDeploy);
        if (insert == 1) {
            log.info("新增成功{}", JacksonUtils.toString(admDockerDeploy));
        }
    }

    /**
     * 部署失败
     *
     * @param deployDeploy
     * @param message
     */
    private void deployError(AdmDockerDeploy deployDeploy, String message, Server server) {
        try {
            deployDeploy.setDeployStatus(DockerDeployStatusEnum.DOCKER_FAILED.getCode());
            admDockerDeployMapper.updateById(deployDeploy);
            String info4 = StringUtils.format("{} ERROR {} docker部署到宿主机{},失败，原因：{}", DateUtil.now(), deployDeploy.getModuleName(), server.getIp(), message);
            FileUtils.writeDockerFileInRealTime(info4);
            FileUtils.writeDockerFileByPath(deployDeploy, info4);
            alertFailMsg(StringUtils.format("{}docker部署失败", deployDeploy.getModuleName()));
        } catch (Exception e) {

        }

    }
}
